package com.base.web.socket.utils;

import java.io.IOException;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.base.common.Constants;
import com.base.common.utils.R;
import com.base.web.socket.entity.ChatMessage;


@ServerEndpoint("/im/{userId}")
@Component
public class WebSocketServer {

	private static Logger log = LoggerFactory.getLogger(WebSocketServer.class);
	// 静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
	private static int onlineCount = 0;
	// 旧：concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
	// private static CopyOnWriteArraySet<ImController> webSocketSet = new
	// CopyOnWriteArraySet<ImController>();
	// 与某个客户端的连接会话，需要通过它来给客户端发送数据
	private Session session;
	// 新：使用map对象，便于根据userId来获取对应的WebSocket
	private static ConcurrentHashMap<String, WebSocketServer> websocketList = new ConcurrentHashMap<>();
	
	// 接收sid
	private String userId = "";
	
	/**
	 * 连接建立成功调用的方法
	 */
	@OnOpen
	public void onOpen(Session session, @PathParam("userId") String userId) {
		this.session = session;
		websocketList.put(userId, this);
		log.info("websocketList->" + JSON.toJSONString(websocketList));
		// webSocketSet.add(this); //加入set中
		addOnlineCount(); // 在线数加1
		this.userId = userId;
		try {
			sendMessage(JSON.toJSONString(R.ok("连接成功")));
			
			SysUserUtils.uptSysUserStatus(1, userId);
			sendMsgAllUser(Constants.SOCKET_USER_ONLINE, "有好友上线了");
			log.info("有新窗口开始监听:" + userId + ",当前在线人数为" + getOnlineCount());
		} catch (IOException e) {
			log.error("websocket IO异常");
		}
	}

	/**
	 * 连接关闭调用的方法
	 */
	@OnClose
	public void onClose() {
		if (websocketList.get(this.userId) != null) {
			websocketList.remove(this.userId);
			// webSocketSet.remove(this); //从set中删除
			subOnlineCount(); // 在线数减1
			
			SysUserUtils.uptSysUserStatus(0, userId);
			sendMsgAllUser(Constants.SOCKET_USER_OFFLINE, "有好友下线了");
			log.info("有一连接关闭！当前在线人数为" + getOnlineCount());
		}
	}

	/**
	 * 收到客户端消息后调用的方法
	 *
	 * @param message
	 *            客户端发送过来的消息
	 */
	@OnMessage
	public void onMessage(String message, Session session) {
		log.info("收到来自窗口" + userId + "的信息:" + message);
		
		if (StringUtils.isNotBlank(message)) {
			JSONObject jsonObject = JSONObject.parseObject(message);
			String friendId = jsonObject.getString("friendId");
			String friendName = jsonObject.getString("friendName");
			String myName = jsonObject.getString("myName");
			String content = jsonObject.getString("content");
			
			// 传送给对应用户的websocket
			if (StringUtils.isNotBlank(friendId) && StringUtils.isNotBlank(content)) {
				WebSocketServer socketx = websocketList.get(friendId);
				// 保存聊天数据
				ChatMsgUtils.saveMsg(new ChatMessage(friendId, friendName, content), this.userId, myName);
				try {
					if (socketx != null) {
						jsonObject.put("friendId", this.userId); //返回给接收者，好友ID为当前的userId
						socketx.sendMessage(JSON.toJSONString(R.ok(jsonObject)));
					}else {
						sendMessage(JSON.toJSONString(R.error(Constants.SOCKET_SERVER_OFFLINE, "对方已经下线")));
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 *
	 * @param session
	 * @param error
	 */
	@OnError
	public void onError(Session session, Throwable error) {
		log.error("发生错误");
		error.printStackTrace();
	}

	/**
	 * 实现服务器主动推送
	 */
	public void sendMessage(String message) throws IOException {
		this.session.getBasicRemote().sendText(message);
	}
	
	/**
	 * 给其他在线用户发送消息
	 */
	private void sendMsgAllUser(int code, String message) {
		for (Entry<String, WebSocketServer> entry : websocketList.entrySet()) {
			if(this.userId.equals(entry.getKey())) {
				continue;
			}
			try {
				WebSocketServer socketx = entry.getValue();
				if(null != socketx) {
					socketx.sendMessage(JSON.toJSONString(R.ok(code, message).put("userId", entry.getKey())));
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 群发自定义消息
	 */
	// public static void sendInfo(String message,@PathParam("userId") String
	// userId) throws IOException {
	// log.info("推送消息到窗口"+userId+"，推送内容:"+message);
	// for (ImController item : webSocketSet) {
	// try {
	// //这里可以设定只推送给这个sid的，为null则全部推送
	// if(userId==null) {
	// item.sendMessage(message);
	// }else if(item.userId.equals(userId)){
	// item.sendMessage(message);
	// }
	// } catch (IOException e) {
	// continue;
	// }
	// }
	// }

	public static synchronized int getOnlineCount() {
		return onlineCount;
	}

	public static synchronized void addOnlineCount() {
		WebSocketServer.onlineCount++;
	}

	public static synchronized void subOnlineCount() {
		WebSocketServer.onlineCount--;
	}
}
